﻿using WQLWebAPI.Domain.Abstract;
using WQLWebAPI.Domain.Entities;
using WQLWebAPI.Infrastructure.CommonDtos;
using Microsoft.Extensions.Configuration;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace WQLWebAPI.Mongodb
{
    public class MongoBaseRepository<T> : IBaseRepository<T> where T : Entity
    {


        private string _connectionStr;
        private string _databaseStr;
        public MongoBaseRepository(IConfiguration config)
        {

            _connectionStr = config.GetSection("MongoDb")["ConnectionString"];
            _databaseStr = config.GetSection("MongoDb")["DatabaseName"];
        }

        public virtual IMongoDatabase Database
        {
            get
            {

                //var client = new MongoClient(_mongoConnection.GetConnectionString());
                //var database = client.GetDatabase(_mongoConnection.GetDatabaseName());

                var client = new MongoClient(_connectionStr);
                var database = client.GetDatabase(_databaseStr);
                return database;
            }
        }
        public virtual IMongoCollection<T> Collection
        {
            get
            {
                return Database.GetCollection<T>(typeof(T).Name);
            }
        }

        public virtual List<T> Get()
        {

            var temp = Collection.Find(d => true).ToList();
            return temp;
        }
        public virtual async Task<List<T>> GetAsync()
        {

            return await Collection.Find(book => true).ToListAsync();
        }
        public virtual async Task<List<T>> GetAsync(Expression<Func<T, bool>> filter, FindOptions options = null)
        {

            return await Collection.Find(filter, options).ToListAsync();
        }
        public virtual async Task<T> FirstOrDefaultAsync(string id)
        {
            return await Collection.Find<T>(book => book.Id == id).FirstOrDefaultAsync();
        }
        public virtual async Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> filter, FindOptions options = null)
        {
            return await Collection.Find(filter, options).FirstOrDefaultAsync();
        }

        public virtual async Task<T> CreateAsync(T book)
        {
            book.CreateDate = DateTime.Now;
            //await Collection.Indexes.CreateOneAsync(new CreateIndexModel<T>(Builders<T>.IndexKeys.Descending(d => d.Date)));
            await Collection.InsertOneAsync(book);

            return book;
        }
        public virtual async Task CreateManyAsync(IEnumerable<T> book)
        {
            book.ToList().ForEach(d => d.CreateDate = DateTime.Now);

            //await Collection.Indexes.CreateOneAsync(new CreateIndexModel<T>(Builders<T>.IndexKeys.Descending(d => d.Date)));
            await Collection.InsertManyAsync(book);
            //return Task.CompletedTask;
        }

        public virtual async Task<bool> UpdateAsync(string id, T bookIn)
        {
            bookIn.UpdateDate = DateTime.Now;

            var result = await Collection.ReplaceOneAsync(book => book.Id == id, bookIn);
            return result.ModifiedCount > 0;
        }

        public virtual async Task<bool> RemoveAsync(T bookIn)
        {
            var result = await Collection.DeleteOneAsync(book => book.Id == bookIn.Id);
            return result.DeletedCount > 0;
        }
        public virtual async Task<bool> RemoveAsync(List<string> ids)
        {
            var result = await Collection.DeleteManyAsync(ds => ids.Contains(ds.Id));
            return result.DeletedCount > 0;
        }

        public virtual async Task<bool> RemoveAsync(string id)
        {

            var result = await Collection.DeleteOneAsync(book => book.Id == id);
            return result.DeletedCount > 0;
        }

        public virtual async Task<List<T>> GetAsync(Expression<Func<T, bool>> filter)
        {            
            return await Collection.Find(filter).ToListAsync();
        }

        public virtual async Task<List<T>> GetAsync(FilterDefinition<T> filter)
        {
            return await Collection.Find(filter).ToListAsync();
        }

        public virtual async Task<Pagelist<T>> GetAsync(FilterDefinition<T> filter, PageInputByDateDto pageInput)
        {
             var builder = Builders<T>.Filter;
            if (pageInput.StartTime != null && pageInput.EndTime != null)
            {
                var dateFilter = builder.Where(d => d.UpdateDate <= pageInput.EndTime && d.UpdateDate >= pageInput.StartTime);
                var filters = filter == null ? dateFilter : builder.And(dateFilter, filter);
                return await GetAsync(filters, (PageInputDto)pageInput);
            }
            return await GetAsync(filter, (PageInputDto)pageInput);
        }

        public virtual async Task<Pagelist<T>> GetAsync(FilterDefinition<T> filter, PageInputDto pageInput)
        {
            if (filter == null) filter = new BsonDocument();//mongodb过滤不允许为空
            var pagedList = new Pagelist<T>();
            var result = new List<T>();
            var entitys = Collection.Find(filter);
            var count= await entitys.CountDocumentsAsync();
            if (pageInput.PageSize == 0)
            {
                //排序
                if (pageInput.Isdesc)
                {
                    result = await entitys.SortByDescending(d => d.Id).ToListAsync();
                    
                }
                else
                {
                    result = await entitys.ToListAsync();

                }
 
            }
            else
            {
                //排序
                if (pageInput.Isdesc)
                {
                    result = await entitys.SortByDescending(d => d.Id).Skip((pageInput.Page - 1) * pageInput.PageSize).Limit(pageInput.PageSize).ToListAsync();

                }
                else
                {
                    result = await entitys.Skip((pageInput.Page - 1) * pageInput.PageSize).Limit(pageInput.PageSize).ToListAsync();

                }

            }
            pagedList.Data.AddRange(result);
            pagedList.TotalCount = count;
            pagedList.PageSize = pageInput.PageSize;



            return pagedList;
        }
        public virtual List<T> Get(FilterDefinition<T> filter, PageInputDto pageInput)
        {
            if (filter == null) filter = new BsonDocument();//mongodb过滤不允许为空
            var pagedList = new Pagelist<T>();
            var entitys = Collection.Find(filter);
            var result = new List<T>();
            if (pageInput.PageSize == 0)
            {
                //排序
                if (pageInput.Isdesc)
                {
                    result = entitys.SortByDescending(d => d.Id).ToList();

                }
                else
                {
                    result = entitys.ToList();

                }

            }
            else
            {
                //排序
                if (pageInput.Isdesc)
                {
                    result = entitys.SortByDescending(d => d.Id).Skip((pageInput.Page - 1) * pageInput.PageSize).Limit(pageInput.PageSize).ToList();

                }
                else
                {
                    result = entitys.Skip((pageInput.Page - 1) * pageInput.PageSize).Limit(pageInput.PageSize).ToList();

                }

            }
            pagedList.Data.AddRange(result);
            pagedList.TotalCount = entitys.CountDocuments();
            pagedList.PageSize = pageInput.PageSize;



            return result;
        }

      
    }
}
